﻿
/* $Id: NetBuffer.cs 2 2011-03-29 13:12:21Z nramsbottom@gmail.com $ */

using System;

namespace SimpleNetServer
{

	class NetBuffer
	{

		private byte[] _buffer { get; set; }

		/// <summary>
		/// Capacity of the buffer;
		/// </summary>
		public int Capacity { get; private set; }

		/// <summary>
		/// Size of the data currently stored in the buffer.
		/// </summary>
		public int Size { get; private set; }

		public NetBuffer(int capacity)
		{
			this.Capacity = capacity;
			this.Size = 0;
			this._buffer = new byte[this.Capacity];
		}

		/// <summary>
		/// Write <paramref name="count"/> bytes from <param name="src"/> onto the end of the buffer.
		/// </summary>
		/// <param name="buffer"></param>
		/// <param name="offset"></param>
		/// <param name="size"></param>
		public void Write(byte[] src, int offset, int count)
		{

			if (this.Size + count > this.Capacity)
				throw new InvalidOperationException("Insufficient storage available.");

			Buffer.BlockCopy(src, offset, _buffer, this.Size, count);
			
			this.Size += count;

		} //

		/// <summary>
		/// Read <paramref name="count"/> bytes from the buffer.
		/// </summary>
		/// <param name="count">The number of bytes to read from the buffer.</param>
		/// <returns>The data read is removed from the buffer.</returns>
		public byte[] Read(int count)
		{
			if (this.Size < count)
				throw new InvalidOperationException("Buffer contains insufficient data to fulfil the request.");

			var buf = new byte[count];

			this.Size -= count;

			Buffer.BlockCopy(this._buffer, 0, buf, 0, count);
			Buffer.BlockCopy(this._buffer, count, this._buffer, 0, this.Size);

			return buf;

		} //

		/// <summary>
		/// Peek at the first byte in the buffer.
		/// </summary>
		/// <returns>Peeking does not remove the data from the buffer.</returns>
		public byte Peek()
		{
			if (this.Size == 0)
				throw new InvalidOperationException("Buffer is empty.");
			return this._buffer[0];
		} //

		/// <summary>
		/// Peek at up to <paramref name="count"/> bytes in the buffer.
		/// </summary>
		/// <param name="count"></param>
		/// <returns></returns>
		/// <exception cref="System.InvalidOperationException">Thrown if <paramref name="count"/> exceeds the size of the data within the buffer.</exception>
		public byte[] Peek(int count)
		{
			if (this.Size < count)
				throw new InvalidOperationException("Buffer contains insufficient data to fulfil the request.");
			
			var buf = new byte[count];

			Buffer.BlockCopy(this._buffer, 0, buf, 0, count);

			return buf;

		} //

		/// <summary>
		/// Determines if the current buffer can store it's current contents plus <paramref name="count"/> bytes.
		/// </summary>
		/// <param name="count"></param>
		/// <returns></returns>
		public bool HasCapacity(int count)
		{
			return this.Size + count <= this.Capacity;
		}

	} // class

} // namespace
